/*!
 * \file HftStrategyMgr.cpp
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief HFT策略管理器实现文件
 * 
 * 本文件实现了HFT(High Frequency Trading)策略管理器的核心功能，
 * 包括策略工厂的动态加载、策略实例的创建和管理等。支持从指定目录
 * 加载策略工厂DLL/SO文件，并提供策略实例的创建、查找和生命周期管理。
 */
#include "HftStrategyMgr.h"

#include <boost/filesystem.hpp>

#include "../Share/StrUtil.hpp"
#include "../Share/StdUtils.hpp"

#include "../WTSTools/WTSLogger.h"

/**
 * @brief 构造函数
 * 
 * 初始化HFT策略管理器
 */
HftStrategyMgr::HftStrategyMgr()
{
}

/**
 * @brief 析构函数
 * 
 * 清理资源
 */
HftStrategyMgr::~HftStrategyMgr()
{
}

/**
 * @brief 加载策略工厂
 * 
 * 从指定目录加载所有的HFT策略工厂DLL/SO文件，并初始化策略工厂实例
 * 
 * @param path 策略工厂文件所在目录路径
 * @return 加载成功返回true，失败返回false
 */
bool HftStrategyMgr::loadFactories(const char* path)
{
	// 检查目录是否存在
	if (!StdFile::exists(path))
	{
		WTSLogger::error("Directory %s of HFT strategy factory not exists", path);
		return false;
	}

	uint32_t count = 0;
	boost::filesystem::path myPath(path);
	boost::filesystem::directory_iterator endIter;
	
	// 遍历目录中的所有文件
	for (boost::filesystem::directory_iterator iter(myPath); iter != endIter; iter++)
	{
		// 跳过子目录
		if (boost::filesystem::is_directory(iter->path()))
			continue;

		// 根据平台检查文件扩展名
#ifdef _WIN32
		if (iter->path().extension() != ".dll")
			continue;
#else //_UNIX
		if (iter->path().extension() != ".so")
			continue;
#endif

		// 加载动态库
		DllHandle hInst = DLLHelper::load_library(iter->path().string().c_str());
		if (hInst == NULL)
			continue;

		// 获取创建工厂函数
		FuncCreateHftStraFact creator = (FuncCreateHftStraFact)DLLHelper::get_symbol(hInst, "createStrategyFact");
		if (creator == NULL)
		{
			DLLHelper::free_library(hInst);
			continue;
		}
		
		// 创建HFT策略工厂实例
		IHftStrategyFact* pFact = creator();
		if (pFact != NULL)
		{
			// 保存工厂信息
			StraFactInfo& fInfo = _factories[pFact->getName()];

			fInfo._module_inst = hInst;
			fInfo._module_path = iter->path().string();
			fInfo._creator = creator;
			fInfo._remover = (FuncDeleteHftStraFact)DLLHelper::get_symbol(hInst, "deleteStrategyFact");
			fInfo._fact = pFact;
			WTSLogger::info("HFT strategy factory[%s] loaded", pFact->getName());

			count++;
		}
		else
		{
			// 创建失败，释放库
			DLLHelper::free_library(hInst);
			continue;
		}
	}

	WTSLogger::info("%u HFT strategy factories in directory[%s] loaded", count, path);

	return true;
}

/**
 * @brief 创建策略实例（通过工厂名和策略名）
 * 
 * 根据指定的工厂名和策略名创建HFT策略实例
 * 
 * @param factname 策略工厂名称
 * @param unitname 策略单元名称
 * @param id 策略实例ID
 * @return 策略实例智能指针，失败返回空指针
 */
HftStrategyPtr HftStrategyMgr::createStrategy(const char* factname, const char* unitname, const char* id)
{
	// 查找策略工厂
	auto it = _factories.find(factname);
	if (it == _factories.end())
		return HftStrategyPtr();

	// 创建策略实例
	StraFactInfo& fInfo = (StraFactInfo&)it->second;
	HftStrategyPtr ret(new HftStraWrapper(fInfo._fact->createStrategy(unitname, id), fInfo._fact));
	_strategies[id] = ret;
	return ret;
}

/**
 * @brief 创建策略实例（通过策略名称）
 * 
 * 根据策略名称创建HFT策略实例，策略名称格式为"工厂名.策略名"
 * 
 * @param name 策略名称，格式为"factname.unitname"
 * @param id 策略实例ID
 * @return 策略实例智能指针，失败返回空指针
 */
HftStrategyPtr HftStrategyMgr::createStrategy(const char* name, const char* id)
{
	// 解析策略名称
	StringVector ay = StrUtil::split(name, ".");
	if (ay.size() < 2)
		return HftStrategyPtr();

	const char* factname = ay[0].c_str();
	const char* unitname = ay[1].c_str();

	// 查找策略工厂
	auto it = _factories.find(factname);
	if (it == _factories.end())
		return HftStrategyPtr();

	// 创建策略实例
	StraFactInfo& fInfo = (StraFactInfo&)it->second;
	HftStrategyPtr ret(new HftStraWrapper(fInfo._fact->createStrategy(unitname, id), fInfo._fact));
	_strategies[id] = ret;
	return ret;
}

/**
 * @brief 获取策略实例
 * 
 * 根据策略ID获取已创建的HFT策略实例
 * 
 * @param id 策略实例ID
 * @return 策略实例智能指针，不存在返回空指针
 */
HftStrategyPtr HftStrategyMgr::getStrategy(const char* id)
{
	auto it = _strategies.find(id);
	if (it == _strategies.end())
		return HftStrategyPtr();

	return it->second;
}